import { Directive, ElementRef, Input, AfterViewInit } from '@angular/core';
//Controls
import { AmChartsService } from "@amcharts/amcharts3-angular";
import { ClusterModelWrapper } from '../../../modules/research/riskCluster/cluster.model';

@Directive({
  selector: '[intervalChart]'
})
export class IntervalChartDirective implements AfterViewInit {
  private chart: any;

  private _currentClusterName: string = '';
  private _chartData: number = 0;
  private _graphs: any[] = [];
  private _values: any = {};
  private _clusters: ClusterModelWrapper[];
  private _companyCode: string;

  // Assessments are static
  private _assessments: ClusterModelWrapper[] = [
    new ClusterModelWrapper(5, '5', 'Laggard', 'Laggard', '#F0AB01', 20),
    new ClusterModelWrapper(4, '4', 'Underperformer', 'Underperf.', '#F3BC33', 40),
    new ClusterModelWrapper(3, '3', 'Average Performer', 'Avg. Perf.', '#F6CD66', 60),
    new ClusterModelWrapper(2, '2', 'Outperformer', 'Outperf.', '#F9DD99', 80),
    new ClusterModelWrapper(1, '1', 'Leader', 'Leader', '#CCCCCC', 100)
  ];

  @Input() chartID: string;

  @Input() set companyCode(value: string) {
    this._companyCode = value;
    if (this.chart) {
      this._graphs = [];
      this.clusters = this._clusters;
    }
  }

  @Input() axisReversed = false;
  @Input() clustersReversed = false;
  @Input() alphas = 0;
  @Input() addPlus = false;
  @Input() colors;

  // passes enum, and companyCode should be corresponding numeric value
  @Input() set isAssessment(value: boolean) {
    if (value == true) {
      this.clusters = this._assessments;
    }
  }

  @Input() set clusters(value: ClusterModelWrapper[]) {
    if (value) {
      this._clusters = value;

      //get cluster count and set size for each cluster from total of 100
      for (let i = 0; i < value.length; i++) {
        if (value[i].code.toString() === this._companyCode.toString()) {
          this._currentClusterName = value[i].shortName || value[i].name || this._assessments[i].shortName;
        }

        const axisLabel = this.clustersReversed
          ? (value[i].topInterval + '-' + (i === (value.length - 1) ? 0 : value[i + 1].topInterval))
          : (i === 0 ? 0 : value[i - 1].topInterval) + '-' + value[i].topInterval
          ;

        //add graphs
        this._graphs.push({
          fillAlphas: this.alphas,
          lineAlpha: this.alphas,
          showBalloon: false,
          type: "column",
          labelText: value[i].code == this._companyCode ? "" : (value[i].shortName || this._assessments[i].shortName),
          labelPosition: "middle",
          lineColor: this.colors ? this.colors[i] : value[i].color || this._assessments[i].color,
          valueField: value[i].code,
          axisLabel: axisLabel + (this.addPlus && i === value.length - 1 ? '+' : ''),
        });
        //set graph values
        this._values[value[i].code] = 100 / value.length;
      }

      if (this.chart) {
        this.AmCharts.updateChart(this.chart, () => {
          this.chart.dataProvider = [this._values];
          this.chart.graphs = this._graphs;
        });

        this.buildAxis(this.chart.categoryAxis.x);
      }
    }
  }

  @Input() showAxis = true;
  @Input() showText = true;
  @Input() showClusterNameInAxis = false;
  @Input() axisOnTop = false;
  @Input() arrowPositionY = -15;
  @Input() currentValue;
  @Input() subindustryExposureScore;

  constructor(private el: ElementRef, private AmCharts: AmChartsService) { }

  ngAfterViewInit() {
    //prepare chart using the input risk levels
    this.chart = this.AmCharts.makeChart(this.chartID, {
      type: "serial",
      autoMargins: false,
      addClassNames: true,
      marginTop: this.showAxis ? 12 : 0,
      marginLeft: 0,
      marginBottom: this.showAxis ? 25 : 0,
      marginRight: 0,
      width: '100%',
      height: 40,
      valueAxes: [{
        stackType: "regular",
        gridAlpha: 0,
        axisAlpha: 0,
        maximum: 100,
        labelsEnabled: false
      }],
      dataProvider: [this._values],
      startDuration: 0, //animation disabled because of angular2-ie9-shims making it slow
      graphs: this._graphs,
      rotate: true,
      columnWidth: 1,
      categoryAxis: {
        gridAlpha: 0,
        axisAlpha: 0,
        labelsEnabled: false
      },
      listeners: [{
        event: "rendered",
        method: (e) => {
          if (this.chart == undefined) this.chart = e.chart;
          if (this._values) {
            this.buildAxis(e.chart.categoryAxis.x);
          }
        }
      },
      {
        event: "resized",
        method: (e) => {
          this.buildAxis(e.chart.categoryAxis.x);
        }
      }]
    });
  }

  ngOnDestroy() {
    this.AmCharts.destroyChart(this.chart);
  }

  private buildAxis(startLocation: number): void {
    if (this.chart.valueAxes.length == 0 || this.chart.valueAxes[0].data == undefined) return;

    var minInterval = 0;
    var htmlContent = '', style = '', textStyle = '', distributionTextDiv = '';
    var element = document.createElement('canvas');
    var context = element.getContext("2d");
    context.font = "14px Calibri";

    //#FML
    var graphs = this.chart.valueAxes[0].data[0].axes[this.chart.valueAxes[0].id].graphs;
    var graphElements = Object.keys(graphs);

    Object.keys(graphs).forEach(element => {
      if (graphs[element].graph.type == 'column') {
        style = 'float: left;height: 100%;';
        textStyle = 'text-align: center;font-size: 8pt;margin-top:-5px;';

        if (graphs[element].graph.valueField == this.companyCode) {
          //style += 'font-weight: 900;';
          var className = "amcharts-graph-" + graphs[element].graph.id;
          var items = document.getElementsByClassName(className);
          items[0].parentElement.style.backgroundColor = "black";
        }

        if (graphs[element].values.open == 0) {
          style += 'margin-left:' + startLocation + 'px;';
        }

        style += 'width:' + graphs[element].columnWidth + 'px;';

        let text = graphs[element].graph.axisLabel;
        if (this.showClusterNameInAxis) {
          const label = graphs[element].graph.valueField === this._companyCode.toString()
            ? this._currentClusterName
            : graphs[element].graph.labelText;
          text = '<strong>' + label + '</strong><br />' + text;
        }

        distributionTextDiv = `<p class="text-center chart-legend" style="${textStyle}">${text}</p>`;

        if (this.showAxis) {
          htmlContent += "<div style='" + style + "'>" + distributionTextDiv + "</div>";
        }
      }
    }, this);

    const axisElement = `${this.chartID}Axis`;
    this.el.nativeElement.children[axisElement].innerHTML = htmlContent;
    this.selectCluster(startLocation);
  }

  private selectCluster(startLocation: number): void {

    const graphs = this.chart.valueAxes[0].data[0].axes[this.chart.valueAxes[0].id].graphs;
    Object.keys(graphs).forEach((element, index) => {
      // setup vars
      const isSelected = graphs[element].graph.valueField.toString() === this._companyCode.toString();
      const isDisabled = index > 0 && (
        ((this.axisReversed && graphs[element].graph.valueField.toString() > this._companyCode.toString()) // risk rating
          || (!this.axisReversed && graphs[element].graph.valueField.toString() < this._companyCode.toString()) // esg rating
        ) || this._companyCode === 'X' // negligible
      );

      // get style
      const style = this.getClusterStyle(graphs, element, index, isSelected, isDisabled);

      // text to display
      const displayText = isSelected
        ? this._currentClusterName
        : graphs[element].graph.labelText;

      // arrow
      const columnPosition = this.getColumnPosition(index, this.currentValue);
      const arrowOffset = 3;
      const columnIndex = index;
      const arrowPosX = graphs[element].graph.x + (columnIndex * graphs[element].columnWidth) + graphs[element].columnWidth * columnPosition - arrowOffset;
      const arrowPosY = this.arrowPositionY;

      const arrow = `
        <div style="position: absolute; top: ${arrowPosY}px; left: ${arrowPosX}px">
          <img height="10" width="10" src="https://risk-rating-images.s3-eu-west-1.amazonaws.com/Live/ArrowHead.PNG">
        </div>`;

      const subindustryColumnPosition = this.getColumnPosition(index, this.subindustryExposureScore);
      const subArrowPosX = graphs[element].graph.x + (columnIndex * graphs[element].columnWidth) + graphs[element].columnWidth * subindustryColumnPosition - arrowOffset;

      const subArrow = `
        <div style="position: absolute; top: 44px; left: ${subArrowPosX}px; transform: scale(-1, -1);">
          <img height="10" width="10" src="https://risk-rating-images.s3-eu-west-1.amazonaws.com/Live/ArrowHead.PNG">
        </div>`;

      // content
      const htmlContent = '' + (isSelected ? arrow  : '') + (isSelected && this.subindustryExposureScore ? subArrow  : '') + `
        <div style="position: absolute; ${style}">
          <span style="${this.getClusterTextStyle(graphs, element, isSelected)}">
            <strong>${this.showText ? displayText : ''}</strong>
          </span>
        </div>
      `;

      // add to DOM
      const axisElement = `${this.chartID}Axis`;

      this.el.nativeElement.children[axisElement].innerHTML += htmlContent;
      return;
    });
  }

  private getClusterStyle(graphs, element, index, isSelected = false, isDisabled = false): string {
    const borderWidth = 1;
    const width = graphs[element].columnWidth + borderWidth;

    // base style
    const top = this.axisOnTop ? 25 : 1;
    let style = `
      height: ${(graphs[element].columnHeight + borderWidth / 2)}px;
      left: ${(graphs[element].graph.x + (index * graphs[element].columnWidth)) + 1}px;
      top: ${(graphs[element].graph.y + top)}px;
      width: ${width}px;
    `;

    if (isSelected) {
      style += `
        z-index: 999;
        border: ${borderWidth}px black solid;
        background: ${graphs[element].graph.lineColor};
        width: ${width - 1}px;
      `;
    } else if (isDisabled) {
      style += `
        border: ${borderWidth}px #CCC solid;
        background: #FFF;
        color: #CCC;
      `;
    } else {
      style += `
        border: ${borderWidth}px ${graphs[element].graph.lineColor} solid;
        background: ${graphs[element].graph.lineColor};
      `;
    }

    return style;
  }

  private getClusterTextStyle(graphs, element, isSelected): string {
    //selected element must take into consideration the border width, and reduce it
    return `
      display: block;
      vertical-align: middle;
      text-align: center;
      line-height: ${graphs[element].columnHeight}px;
      font-size: 11px;
    `;
  }

  private getColumnPosition(index, value) {
    const topInterval = this._clusters[index].topInterval;
    let prevTopInterval: number;

    // set top intverval
    if (this.clustersReversed) {
      prevTopInterval = index === this._clusters.length - 1 ? 0 : this._clusters[index + 1].topInterval;
    } else {
      prevTopInterval = index === 0 ? 0 : this._clusters[index - 1].topInterval;
    }

    // calc arrow position
    const totalRange = topInterval - prevTopInterval;
    const columnPosition = (totalRange - (this._clusters[index].topInterval - value)) / totalRange;

    return this.clustersReversed ? 1 - columnPosition : columnPosition;
  }
}
